package edu.uwm.cs552.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

import javax.swing.SwingUtilities;


public class Clock implements Runnable {
	
	private static Clock instance = new Clock();
	//immutableCol is immutable and volatile and protected by a lock on itself
	private volatile Collection<ClockListener> immutableCol;
	
	private Clock() {
		ArrayList<ClockListener> list = new ArrayList<ClockListener>();
		immutableCol = Collections.unmodifiableCollection(list);
	}
	
	public static Clock getInstance() {
		return instance;
	}
	
	public void addListener(Runnable runnable, int millis) {
		synchronized (immutableCol) {
			ArrayList<ClockListener> list = new ArrayList<ClockListener>();
			for (ClockListener l : immutableCol) {
				list.add(l);
			}
			list.add(new ClockListener(runnable, millis));
			immutableCol = Collections.unmodifiableCollection(list);
		}
	}
	
	private void alert() {
		for (ClockListener l : immutableCol) {
			l.alert();
		}
	}
	
	private class ClockListener {
		private Runnable runnable;
		private int waitTime; //in millis
		private int runCount;
		private long startTime;
		
		public ClockListener(Runnable r, int m) {
			runnable = r;
			waitTime = m;
			runCount = 0;
			startTime = System.currentTimeMillis();
		}
		
		public void alert() {
			long currentTime = System.currentTimeMillis();
			long expectedRunCount = (currentTime - startTime) / waitTime;
			if (expectedRunCount > runCount) {
				SwingUtilities.invokeLater(runnable);
				++runCount;
			}
			
		}
	}

	@Override
	public void run() {
		try {
			for (;;) {
				synchronized (this) {
					alert();
					wait(50);
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
